package com.hi.hiparty.jdbc;

import java.sql.Connection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.digester.Digester;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.orm.ibatis.SqlMapClientFactoryBean;
import org.springframework.orm.ibatis.SqlMapClientTemplate;

import com.ibatis.sqlmap.client.SqlMapClient;

public final class SqlMapClientTemplateCache {
	private static final Log LOG = LogFactory
			.getLog(SqlMapClientTemplateCache.class);

	private SqlMapClientTemplateCache() {
		super();
	}

	private static Map<String, SqlMapClientTemplate> SQLCLIENTCACHE = new ConcurrentHashMap<String, SqlMapClientTemplate>();
	private static Object lock = new Object();
	static {
		initDbInfoMap();
	}

	@SuppressWarnings("unchecked")
	private static void initDbInfoMap() {
		Digester digester;
		ClassPathResource resource;
		try {
			digester = new Digester();
			digester.setValidating(false);
			digester.addObjectCreate("datasources", LinkedList.class);
			digester.addObjectCreate("datasources/datasource", DbInfo.class);
			digester.addBeanPropertySetter("datasources/datasource/name",
					"name");
			digester.addBeanPropertySetter("datasources/datasource/jndi-name",
					"jndiName");
			digester.addBeanPropertySetter("datasources/datasource/driver",
					"driver");
			digester.addBeanPropertySetter("datasources/datasource/url", "url");
			digester.addBeanPropertySetter("datasources/datasource/username",
					"username");
			digester.addBeanPropertySetter("datasources/datasource/password",
					"password");
			digester.addSetNext("datasources/datasource", "add");
			System.out.println(System.getProperty("java.class.path") );
			resource = new ClassPathResource("datasource.xml");
			List<DbInfo> list = (List<DbInfo>) digester.parse(resource
					.getInputStream());
			for (DbInfo info : list) {
				try {
					String dBName = info.getName();
					DataSource dataSource = getDataSource(info);
					SqlMapClientFactoryBean factory = new SqlMapClientFactoryBean();
					factory.setDataSource(dataSource);
					factory.setConfigLocation(new ClassPathResource(
							"sql-map-config.xml"));
					factory.afterPropertiesSet();
					SqlMapClient sqlMapClient = (SqlMapClient) factory
							.getObject();
					SqlMapClientTemplate template = new SqlMapClientTemplate(
							sqlMapClient);
					SQLCLIENTCACHE.put(dBName, template);
					LOG.info("initDbInfoMap dBName:[ " + dBName + " ]"
							+ " template:[ " + template + " ]");
				} catch (Exception e) {
					e.printStackTrace();
					LOG.info("initDbInfoMap ERROR:[ " + e + " ]");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			LOG.info("SQL INITIALIZE ERROR :" + e);
		}
	}

	public static DataSource getDataSource(final DbInfo info) {
		if (info == null) {
			throw new IllegalArgumentException(
					"The name of the database MUST NOT BE NULL");
		}
		String name = info.getName();
		if (StringUtils.isBlank(name)) {
			throw new IllegalArgumentException("Can not get datasource name");
		}
		synchronized (lock) {
			BasicDataSource ds = new BasicDataSource();
			ds.setDriverClassName(info.getDriver());
			ds.setUsername(info.getUsername());
			ds.setPassword(info.getPassword());
			ds.setUrl(info.getUrl());
			Connection con = DataSourceUtils.getConnection(ds);
			if (con != null) {
				DataSourceUtils.releaseConnection(con, ds);
				if (LOG.isInfoEnabled()) {
					LOG.info("Getting standalone datasource [" + ds
							+ "] with name [" + name + "]");
				}
				return ds;
			}
		}
		throw new DataAccessResourceFailureException(
				"Cant get Datasource with name : [" + name + "]");
	}

	public static SqlMapClientTemplate getSqlMapClientTemplate(String database)
			throws Exception {
		return SQLCLIENTCACHE.get(database);
	}

}
